package org.meruvian.yama.service.impl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.json.JSONArray;
import org.json.JSONObject;
import org.springframework.stereotype.Service;

/**
 * This bean provides service methods that invoke the Joget Workflow JSON API
 */
@Service
public class JSONConsumerService {

    public static final String DEFAULT_BASE_URL = "http://localhost:8081/wflow-wfweb";

    private String baseUrl = DEFAULT_BASE_URL;
    
//    public Map<String, Object> getInbox(String username, String password) {
//        Map<String, Object> processMap = new HashMap<String, Object>();
//
//        // form the JSON API URL
//        String params = "j_username=" + username + "&j_password=" + password;
//        String url = getBaseUrl() + "/web/json/workflow/assignment/list?" + params;
//        InputStream in = null;
//
//        // use HttpClient to make an HTTP call to the JSON API
//        HttpClient client = new HttpClient();
//        GetMethod get = new GetMethod(url);
//        try {
//            client.executeMethod(get);
//
//            // read the response
//            in = get.getResponseBodyAsStream();
//            String jsonResponse = streamToString(in);
//            ObjectMapper mapper = new ObjectMapper();
//            Map<String, Object> l = mapper.readValue(jsonResponse, new TypeReference<Map<String, Object>>() {
//			});
//            processMap.putAll(l);
//
//        } catch (Exception e) {
//            Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
//        } finally {
//            try {
//                if (in != null) {
//                    in.close();
//                }
//                get.releaseConnection();
//            } catch (IOException ex) {
//                Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
//            }
//        }
//
//        return processMap;
//    }
    
    public Map<String, Object> getListById(String action, String id, String username, String password) {
        Map<String, Object> processMap = new HashMap<String, Object>();

        // form the JSON API URL
        String params = "j_username=" + username + "&j_password=" + password;
//        String encodedProcessId = null;
//        
//        try {
//            encodedProcessId = URLEncoder.encode(processId, "UTF-8");
//        } catch (UnsupportedEncodingException ex) {
//            encodedProcessId = processId;
//            Logger.getLogger(SampleServiceBean.class.getName()).log(Level.SEVERE, null, ex);
//        }
        String url = ""; 
        if(action.equals("view")){
        	url = getBaseUrl() + "/web/json/monitoring/activity/list?processId="+id+"&" + params;
        }else if(action.equals("viewProcess")){
        	url = getBaseUrl() + "/web/json/monitoring/running/process/list?start=0&processId="+id+"&" + params;
        }else if(action.equals("viewActivity")){
        	url = getBaseUrl() + "/web/json/monitoring/activity/view/"+id+"?" + params;
        }else if(action.equals("viewInboxActivity")){
        	url = getBaseUrl() + "/web/json/workflow/assignment/view/"+id+"?" + params;
        }
        
        InputStream in = null;

        // use HttpClient to make an HTTP call to the JSON API
        HttpClient client = new HttpClient();
        GetMethod get = new GetMethod(url);
        try {
            client.executeMethod(get);

            // read the response
            in = get.getResponseBodyAsStream();
            String jsonResponse = streamToString(in);
            System.out.println(jsonResponse);
            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> l = mapper.readValue(jsonResponse, new TypeReference<Map<String, Object>>() {
			});
            processMap.put("baseUrl", baseUrl);
            processMap.putAll(l);

        } catch (Exception e) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                get.releaseConnection();
            } catch (IOException ex) {
                Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
            }
        }

        return processMap;
    }
    
    public Map<String, Object> getList(String action, String username, String password) {
        Map<String, Object> processMap = new HashMap<String, Object>();

        // form the JSON API URL
        String params = "j_username=" + username + "&j_password=" + password;
        String url = ""; 
        if(action.equals("history")){
        	url = getBaseUrl() + "/web/json/workflow/assignment/history?" + params;
        }else if(action.equals("inbox")){
        	url = getBaseUrl() + "/web/json/workflow/assignment/list?" + params;
        }else if(action.equals("completedProcess")){
        	url = getBaseUrl() + "/web/json/monitoring/completed/process/list?start=0&" + params;
        }else if(action.equals("runningProcess")){
        	url = getBaseUrl() + "/web/json/monitoring/running/process/list?start=0&" + params;
        }else if(action.equals("processList")){
        	url = getBaseUrl() + "/web/json/workflow/process/list?" + params;
        }
        
        InputStream in = null;

        // use HttpClient to make an HTTP call to the JSON API
        HttpClient client = new HttpClient();
        GetMethod get = new GetMethod(url);
        try {
            client.executeMethod(get);

            // read the response
            in = get.getResponseBodyAsStream();
            String jsonResponse = streamToString(in);
            System.out.println(jsonResponse);
            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> l = mapper.readValue(jsonResponse, new TypeReference<Map<String, Object>>() {
			});
            processMap.putAll(l);

        } catch (Exception e) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                get.releaseConnection();
            } catch (IOException ex) {
                Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
            }
        }

        return processMap;
    }
    
    /**
     * Returns the process definitions that are available.
     * @param customBaseUrl
     * @param username
     * @param password
     * @return Map key is the process definition ID, map value is the process name
     */
    public Map<String, Object> getProcessDefList(String username, String password) {
        Map<String, Object> processMap = new HashMap<String, Object>();

        // form the JSON API URL
        String params = "j_username=" + username + "&j_password=" + password;
        String url = getBaseUrl() + "/web/json/workflow/process/list?" + params;
        InputStream in = null;

        // use HttpClient to make an HTTP call to the JSON API
        HttpClient client = new HttpClient();
        GetMethod get = new GetMethod(url);
        try {
            client.executeMethod(get);

            // read the response
            in = get.getResponseBodyAsStream();
            String jsonResponse = streamToString(in);
            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> l = mapper.readValue(jsonResponse, new TypeReference<Map<String, Object>>() {
			});
//            System.out.println(l);
//            JSONObject jsonObj = new JSONObject(jsonResponse);  // find the processes in the response
//            JSONArray array = jsonObj.getJSONArray("data");
//            System.out.println("====== "+array);
            
//            for (int i=0; i<array.length(); i++) {
//                JSONObject process = (JSONObject)array.get(i);
//                String processDefId = (String)process.get("id");
//                processDefId = URLEncoder.encode(processDefId, "UTF-8"); // encode the process definition ID to be suitable as a URL parameter
//                String processName = (String)process.get("label");
//                System.out.println(processDefId);
//                processMap.put(processDefId, processName);
//            }
            
            processMap.putAll(l);
        } catch (Exception e) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                get.releaseConnection();
            } catch (IOException ex) {
                Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
            }
        }

        return processMap;
    }
    
    public String abortProcess(String processDefId, String username, String password) {
        String processInstanceId = null;

        // form the JSON API URL
        String params = "j_username=" + username + "&j_password=" + password;
        String encodedProcessDefId = null;
        try {
            encodedProcessDefId = URLEncoder.encode(processDefId, "UTF-8");
        } catch (UnsupportedEncodingException ex) {
            encodedProcessDefId = processDefId;
            Logger.getLogger(JSONConsumerService.class.getName()).log(Level.SEVERE, null, ex);
        }
        String url = getBaseUrl() + "/web/json/workflow/process/abort/" + encodedProcessDefId + "?" + params;
        InputStream in = null;

        // use HttpClient to make an HTTP call to the JSON API
        HttpClient client = new HttpClient();
        GetMethod get = new GetMethod(url);
        try {
            client.executeMethod(get);

            // read the response
            in = get.getResponseBodyAsStream();
            String jsonResponse = streamToString(in);
//            JSONObject jsonObj = new JSONObject(jsonResponse);
//            processInstanceId = jsonObj.getString("processId");
            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> l = mapper.readValue(jsonResponse, new TypeReference<Map<String, Object>>() {
			});
            processInstanceId = l.get("processId").toString();
        } catch (Exception e) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                get.releaseConnection();
            } catch (IOException ex) {
                Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
            }
        }
        return processInstanceId;
    }

    /**
     * Starts a process based on a process definition ID.
     * @param processDefId
     * @param customBaseUrl
     * @param username
     * @param password
     * @return The process instance ID if the process is successfully started. Otherwise null is returned.
     */
    public String startProcess(String processDefId, String username, String password) {
        String processInstanceId = null;

        // form the JSON API URL
        String params = "j_username=" + username + "&j_password=" + password;
        String encodedProcessDefId = null;
        try {
            encodedProcessDefId = URLEncoder.encode(processDefId, "UTF-8");
        } catch (UnsupportedEncodingException ex) {
            encodedProcessDefId = processDefId;
            Logger.getLogger(JSONConsumerService.class.getName()).log(Level.SEVERE, null, ex);
        }
        String url = getBaseUrl() + "/web/json/workflow/process/start/" + encodedProcessDefId + "?" + params;
        InputStream in = null;

        // use HttpClient to make an HTTP call to the JSON API
        HttpClient client = new HttpClient();
        GetMethod get = new GetMethod(url);
        try {
            client.executeMethod(get);

            // read the response
            in = get.getResponseBodyAsStream();
            String jsonResponse = streamToString(in);
//            JSONObject jsonObj = new JSONObject(jsonResponse);
//            processInstanceId = jsonObj.getString("processId");
            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> l = mapper.readValue(jsonResponse, new TypeReference<Map<String, Object>>() {
			});
            processInstanceId = l.get("processId").toString();
        } catch (Exception e) {
            Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, e);
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
                get.releaseConnection();
            } catch (IOException ex) {
                Logger.getLogger(getClass().getName()).log(Level.SEVERE, null, ex);
            }
        }
        return processInstanceId;
    }

    /**
     * Reads data from an InputStream into a String
     * @param in
     * @return
     * @throws IOException
     */
    protected String streamToString(InputStream in) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        StringBuilder sb = new StringBuilder();
        String line = null;
        try {
            while ((line = reader.readLine()) != null) {
                sb.append(line);
                sb.append("\n");
            }
        } finally {
            in.close();
        }
        return sb.toString();
    }
    
    public String encode(String word) {
		try {
			return URLEncoder.encode(word, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		return null;
	}

    public String getBaseUrl() {
        return baseUrl;
    }

    public void setBaseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
    }

}
